; rdcmd.asm
; Command channel routines for FE3 RAM Disk
;

	.include "rdglobal.inc"
	.include "rdio.inc"
	.include "rddir.inc"
	.include "rdmem.inc"
	.include "rdrel.inc"
	.include "rdmain.inc"
	_IN_RDCMD = 1
	.include "rdcmd.inc"

	.segment "BSS"

cmdwlen:	.res 1
cmdwbuf:	.res 256

cmdrlen:	.res 1
cmdrpos:	.res 1
cmdrbuf:	.res 256

cmdstatus:	.res 1

	.segment "TABLE"

rdhook:		.word rd_cmd	
wrhook:		.word wr_cmd

	.segment "CODE"

; Initialises the command channel status	
cmd_init:	pha
			lda #0
			sta cmdwlen
			sta cmdrlen
			sta cmdrpos
			sta cmdstatus
			pla
			rts

; Initialises the command channel on open
cmd_open:	lda #0
			sta cmdrlen
			sta cmdrpos
			sta cmdwlen
			rts

; Prepares read hook
cmd_chkin:	pha
			lda #<rd_cmd
			sta rdhook
			lda #>rd_cmd
			sta rdhook+1
			pla
			rts

; Reads a byte from the command channel	
cmd_read:	jmp (rdhook)
rd_cmd:		stx save_x
			lda #0					; clear STatus
			sta $90
			ldx cmdrpos
			bne @toread
			jsr cmd_stat
			ldx #0
			beq @doread
@toread:	cpx cmdrlen
			bcc @doread
			ldx #0
			stx cmdrpos
			lda #$40				; ST := EOF
			jsr $FE6A
			lda #$0D
			bne @done
@doread:	lda cmdrbuf, x
			inx
			stx cmdrpos
@done:		ldx save_x
			rts

; Prepares write hook
cmd_ckout:	pha
			lda #<wr_cmd
			sta wrhook
			lda #>wr_cmd
			sta wrhook+1
			lda #0
			sta cmdwlen
			pla
			rts

; Writes a byte to the command channel			
cmd_write:	jmp (wrhook) 
wr_cmd:		stx save_x
			ldx cmdwlen
			sta cmdwbuf, x
			inx
			beq @done
			stx cmdwlen
@done:		ldx save_x
			rts

; Ends command channel I/O 
cmd_clrch:	pha
			stx save_x
			ldx cmdwlen
			beq @done
			lda #0
			sta cmdwbuf, x
			sty save_y
			jsr cmd_exec ; -> execute & clear buf
			ldy save_y
@done:		ldx save_x
			pla
			rts

; Executes a received command string 
cmd_exec:	lda #<cmdwbuf
			sta ptr
			lda #>cmdwbuf
			sta ptr+1
			jsr exec_cmd
			; clear write buffer
			lda #0
			sta cmdwlen	
			rts

; Generates a string from current status for reading & clears status			
cmd_stat:	ldx cmdstatus
			lda stidx_lo, x
			sta @ldptr+1
			lda stidx_hi, x
			sta @ldptr+2
			ldx #0
@ldptr:		lda $FFFF, x
			beq @done
			sta cmdrbuf, x
			inx
			bne @ldptr
@done:		stx cmdrlen
			lda #0			
			sta cmdrpos
			sta cmdstatus
			rts

; Sets current status
cmd_setst:	sta cmdstatus
			rts

; Executes a command
; INPUT:
;	(ptr)	... address of command string (terminated by $0D)
;
exec_cmd:	ldy #0
			ldx #$FF
@srch_cmd:	inx
			lda fn_char,x
			beq unknown
			cmp (ptr), y
			bne @srch_cmd
			iny
			lda fn_lo, x
			sta @callfn+1
			lda fn_hi, x
			sta @callfn+2
@callfn:	jmp $FFFF
			
unknown:	lda #STATUS_SYNTAX_ERROR
			jmp cmd_setst

; Command "U"ser
f_user:		lda (ptr), y
			cmp #'i'
			bne unknown
			lda #STATUS_RESET
			jmp cmd_setst	

	.segment "DATA"

fptr1:	.res 2 

	.segment "CODE"

; Command "S"cratch
f_scratch:	jsr parspref
			jsr setptr1
			lda #'0'
			sta scratchcnt
			sta scratchcnt+1
			jsr dir_find
			bcs notfound
@delloop:	; check if open	
			ldy #DirEntry::type
			lda (ptr), y
			and #FILE_FLAG_OPEN
			beq @donedel
			; inc. file count
			lda #'9'
			inc scratchcnt+1
			cmp scratchcnt+1
			bcs @doneinc
			lda #'0'
			sta scratchcnt+1
			inc scratchcnt
@doneinc:	; delete file
			ldy #DirEntry::bank
			lda (ptr), y
			pha
			ldy #DirEntry::address
			lda (ptr), y
			tay
			pla
			jsr md_free
			; clear dir entry
			jsr dir_del
			; find next
			lda fptr1
			sta ptr
			lda fptr1+1
			sta ptr+1
			jsr dir_find
			bcc @delloop
			
@donedel:	lda #STATUS_SCRATCH_RESULT
			jmp cmd_setst									

notfound:	lda #STATUS_FILE_NOT_FOUND
			jmp cmd_setst

setptr1:	ldx ptr
			ldy ptr+1
			stx fptr1
			sty fptr1+1
			rts

; Command "R"ename
f_rename:	jsr parspref
			jsr setptr1
			; find '='
			ldy #$FF
@eqloop:	iny
			lda (ptr), y
			bne @notend
			jmp unknown
@notend:	cmp #'='
			bne @eqloop
			; found, set str end for new name
			lda #0
			sta (ptr), y
			; check, if new file name exists
			tya
			pha
			jsr dir_find
			pla
			bcc @fexists
			tay
			; set ptr to old name
			jsr moveptr
			; find file
			jsr dir_find
			bcs notfound
			; rename
			lda fptr1
			sta ptr2
			lda fptr1+1
			sta ptr2+1
			ldy #0
@rnloop:	lda (ptr2), y
			sta (ptr), y
			beq @done
			iny
			cpy #MAX_NAME_LENGTH
			bcc @rnloop			
			; done - success
@done:		lda #STATUS_OK
			jmp cmd_setst	

@fexists:	lda #STATUS_FILE_EXISTS
			jmp cmd_setst

; Command "P"osition
f_pos:		lda (ptr), y	; channel
			and #$1F
			jsr chkinfo
			bcc @isopen
			lda #STATUS_NO_CHANNEL
			jmp cmd_setst
@isopen:	bne @tryrel
@norel:		; file pos for non-REL files (SD2IEC style)
			; min. size of argument is 2B (word), max. up to 4B if present.
			iny
			cpy cmdwlen
			bcs @missarg
			lda (ptr), y	; pos low byte
			sta ptr2
			iny
			cpy cmdwlen
			bcs @missarg
			lda (ptr), y	; pos midlo
			sta ptr2+1
			iny
			cpy cmdwlen
			bcs @finarg1
			lda (ptr), y	; pos midhi
			pha
			iny
			cpy cmdwlen
			bcs @finarg2
			lda (ptr), y	; pos high byte
@dofpos:	tay
			pla
;   (ptr2) ... position low word
;	A/Y ...... position high word
;	X ..... channel no.
			jmp fsetpos
@finarg1:	lda #0
			pha
			beq @dofpos
@finarg2:	lda #0
			beq @dofpos
@missarg:	lda #STATUS_SYNTAX_ERROR
			jmp cmd_setst
;			
@tryrel:	; file position for REL files
			pla
			tax
			iny
			lda (ptr), y	; record lo
			pha
			iny
			lda (ptr), y	; record hi
			pha
			iny
			lda (ptr), y	; position in record
			sta ptr2
			dec ptr2
			pla
			tay
			pla
;	A/Y ... record no.
; 	ptr2 .. pos. in record
;	X ..... channel no.
			jmp rel_setp
			

; Adds y+1 to (ptr)
moveptr:	iny
			tya
			clc
			adc ptr
			sta ptr
			bcc @nohi
			inc ptr+1						
@nohi:		rts

; Parses prefix until ':' is found
parspref:	lda (ptr), y
			bne @notnul
			pla
			pla
			jmp unknown
@notnul:	cmp #':'
			beq @done
			iny
			bne parspref
@done:		jmp moveptr			
			
	.segment "RODATA"
	
st_ok:		.byte "00,ok,00,00", 0
st_result:	.byte "01,files scratched,"
scratchcnt:		.byte "00,00", 0
st_error:	.byte "30,syntax error,00,00", 0
st_receof:	.byte "50,record not present,00,00", 0
st_recofl:	.byte "51,overflow in record,00,00", 0
st_toolrg:	.byte "52,file too large,00,00", 0 
st_nopen:	.byte "61,file not open,00,00", 0
st_nfound:	.byte "62,file not found,00,00", 0
st_exists:	.byte "63,file exists,00,00", 0
st_notrack:	.byte "67,illegal track or sector,00,00", 0
st_nchan:	.byte "70,no channel,00,00", 0
st_full:	.byte "72,disk full,00,00", 0
st_init:	.byte "73,ram driver ",VERSION,",00,00", 0

stidx_lo:	.byte <st_ok, <st_result, <st_nopen, <st_nfound, <st_full, <st_init, <st_error, <st_receof
			.byte <st_recofl, <st_toolrg, <st_nchan, <st_exists, <st_notrack
stidx_hi:	.byte >st_ok, >st_result, >st_nopen, >st_nfound, >st_full, >st_init, >st_error, >st_receof
			.byte >st_recofl, >st_toolrg, >st_nchan, >st_exists, >st_notrack

fn_char:	.byte 'u', 's', 'r', 'p', 0
fn_lo:		.byte <f_user, <f_scratch, <f_rename, <f_pos
fn_hi:		.byte >f_user, >f_scratch, >f_rename, >f_pos
